#pragma once
#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <cstring>
#include "InetAddr.hpp"
#include "common.hpp"
#include "log.hpp"
#include <functional>
#include <memory>
namespace SockModel
{
  class Socket;
  using namespace LogModel;
  using namespace InetModel;
  using SockPtr = std::shared_ptr<Socket>;
  // std::shared_ptr<Socket> Sockptr = std::make_shared<Socket>();
  class Socket
  {
  public:
    virtual void SocketOrDie() = 0;
    virtual void SetSocketOper() = 0;
    virtual bool BindOrDie(int port) = 0;
    virtual bool ListenOrDie() = 0;
    virtual SockPtr AcceptOrDie(InetAdrr &client) = 0;
    virtual void Close() = 0;
    virtual int Recv(std::string *out) = 0;
    virtual int Send(std::string &send_str) = 0;
    virtual int Fd() = 0;
    void SocketInit(int port)
    {
      SocketOrDie();
      SetSocketOper();
      BindOrDie(port);
      ListenOrDie();
    }
  };

  class TcpSocket : public Socket
  {
  public:
    TcpSocket() : _sockfd(gsockfd)
    {
    }
    TcpSocket(int sockfd) : _sockfd(sockfd)
    {
    }
    virtual void SocketOrDie() override
    {
      _sockfd = ::socket(AF_INET, SOCK_STREAM, 0);
      if (_sockfd < 0)
      {
        LOG(LogLevel::FATAL) << "socket: fail" << strerror(errno);
        Die(SOCKET_ERR);
      }
      LOG(LogLevel::INFO) << "socket success " << _sockfd;
    }
    virtual void SetSocketOper() override
    {
      int opt = 1;
      int n = ::setsockopt(_sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
      (void)n;
    }
    virtual bool BindOrDie(int port) override
    {
      if (_sockfd < 0)
      {
        return false;
      }

      InetAdrr addr(port);
      int n = ::bind(_sockfd, addr.NetAddr(), addr.NetAddrLen());
      if (n < 0)
      {
        LOG(LogLevel::FATAL) << "bind: fail" << strerror(errno);
        Die(BIND_ERR);
      }
      LOG(LogLevel::INFO) << "bind success " << _sockfd;
      return true;
    }
    virtual bool ListenOrDie() override
    {
      if (_sockfd < 0)
      {
        return false;
      }
      int n = ::listen(_sockfd, backlog);
      if (n < 0)
      {
        LOG(LogLevel::FATAL) << "listen: fail" << strerror(errno);
        Die(LISTEN_ERR);
      }
      LOG(LogLevel::INFO) << "listen success " << _sockfd;
      return true;
    }
    virtual SockPtr AcceptOrDie(InetAdrr &client) override
    {
      // if (client)
      //     return nullptr;
      // LOG(LogLevel::DEBUG)<<"要accept了";
      struct sockaddr_in peer;
      socklen_t socklen = sizeof(peer);
      int newsockfd = ::accept(_sockfd, CONV(&peer), &socklen);
      LOG(LogLevel::DEBUG) << newsockfd;
      if (newsockfd < 0)
      {
        LOG(LogLevel::FATAL) << "accept: fail" << strerror(errno);
        return nullptr;
      }
      InetAdrr addr(peer);
      client = addr;
      return std::make_shared<TcpSocket>(newsockfd);
    }
    virtual void Close() override
    {
      ::close(_sockfd);
    }
    virtual int Fd() override
    {
      return _sockfd;
    }
    virtual int Recv(std::string *out) override
    {
      char buff[1024 * 8];
      ssize_t n = recv(_sockfd, buff, sizeof(buff) - 1, 0);
      if (n < 0)
      {
        LOG(LogLevel::FATAL) << "recv: fail" << strerror(errno);
      }
      buff[n] = 0;
      *out = buff;
      return n;
    }
    virtual int Send(std::string &send_str) override
    {
      int n = send(_sockfd, send_str.c_str(), send_str.size(), 0);
      return n;
    }

  private:
    int _sockfd;
  };
}